/*
 * Copyright 2020 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef _MODEL_H_
#define _MODEL_H_

#include <stdint.h>

#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define MAX_TENSOR_DIMS 4
	
typedef unsigned int size_t;

typedef struct
{
  uint32_t size;
  uint32_t data[MAX_TENSOR_DIMS];
} tensor_dims_t;

typedef enum
{
    kTensorType_FLOAT32 = 0,
    kTensorType_UINT8 = 1,
    kTensorType_INT8 = 2
} tensor_type_t;

typedef struct
{
  float score;
  int index;
} result_t;

enum
{
	OD_BOXES,
	OD_LABELS,
	OD_SCORES,
	OD_NUMS,
};

#define __ALIGNED(x) __attribute__((aligned(x)))

typedef struct
{
	tensor_dims_t dim;
	tensor_type_t type;
	union{
		float* f;
		uint8_t *u8;
		int8_t *i8;
		void* data;
	}data;
}model_output_t;

// image get
extern int GetImage(void *ptr, uint32_t w, uint32_t h, uint32_t c, uint32_t* is_processed);

// model run
void MODEL_AllocateTensor(void* tensorArena, uint32_t size);
int MODEL_Init(const unsigned char *model_data);
uint8_t* MODEL_GetInputTensorData(tensor_dims_t* dims, tensor_type_t* type);
uint8_t* MODEL_GetOutputTensorData(tensor_dims_t* dims, tensor_type_t* type);
float* MODEL_GetODTensorByIdx(uint32_t idx);
// paired call: user need to create the model_output_t struct
uint32_t MODEL_GetOutputNums();
void MODET_getOutput(model_output_t *node);
/************************************************************
exmaple, assume that a SSD model with totally 4-outptus below:

	float* otput, *scores, *labels, *objects;
	uint32_t output_num = MODEL_GetOutputNums();
	model_output_t *node = (model_output_t*)malloc(output_num * sizeof(model_output_t));
	MODET_getOutput(node);
	// init the boxes, scores, labels, objects;
	boxes = node[0].data.f;
	labels = node[1].data.f;
	scores = node[2].data.f;
	objects = node[3].data.f;
	// also, can get the dims-info by: node[x].dim
	// and the type by: node[x].type
************************************************************/

void MODEL_ConvertInput(uint8_t* data, tensor_dims_t* dims, tensor_type_t type);
int MODEL_RunInference(void);
const char* MODEL_GetModelName(void);
void MODEL_GetTopN(const uint8_t* tensorData, int tensorSize, tensor_type_t tensorType,
                   size_t numResults, float threshold, result_t* topResults);

uint8_t* MODEL_Run();
int MODEL_RunOD();
// only run the model, get all the ouptut results
int MODEL_Invoke();

#if defined(__cplusplus)
}
#endif /* __cplusplus */

#endif /* _MODEL_H_ */
